/*
    server.c - 
    Copyright (C) 2010  GUS-PE (Grupo de Usuários Slackware - PE)
   
    Este programa é software livre; você pode redistribuí-lo e/ou
    modificá-lo sob os termos da Licença Pública Geral GNU, conforme
    publicada pela Free Software Foundation; tanto a versão 2 da
    Licença como (a seu critério) qualquer versão mais nova.

    Este programa é distribuído na expectativa de ser útil, mas SEM
    QUALQUER GARANTIA; sem mesmo a garantia implícita de
    COMERCIALIZAÇÃO ou de ADEQUAÇÃO A QUALQUER PROPÓSITO EM
    PARTICULAR. Consulte a Licença Pública Geral GNU para obter mais
    detalhes.
 
    Você deve ter recebido uma cópia da Licença Pública Geral GNU
    junto com este programa; se não, escreva para a Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    02111-1307, USA.
*/

/* Declaração das definições do servidor no 'server.h' */
#include "server.h"

int
server_interpret(userId, messageStr)
{
	fprintf(stdout, "%d: %s\n", userId, messageStr)
}

/* O principal do servidor, o fluxo continuo para receber e enviar as
 * mensagens que passam pelo protocolo, algumas definicoes importantes
 * sao carregadas do header acima.
 * 
 * Esse é o pulo do gato que aprendi durante alguns bons meses de vários
 * testes, falta alguns ajustes. -crudo
 * 
 */

int 
main(void)
{
	int vrf, ret, soq, newsoq;
	int rbytes, users, smax;
	char buf[SZ_STRINGMAX];
	struct sockaddr_in server, client;
	struct pollfd serverpoll[TOT_USERS];
		
	ret = 0; users = 0; smax = 0; vrf = 0;

	server.sin_port = htons(SERVER_PORT);
	server.sin_family = AF_INET;
	server.sin_addr.s_addr = INADDR_ANY;
	
	
	if ((soq = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) 
		return -1;

	ret = 1;
	setsockopt(soq, SOL_SOCKET, SO_KEEPALIVE, (char *) &ret, sizeof (ret));

	if (bind(soq, (struct sockaddr *)&server, sizeof(struct sockaddr)) == -1)
		return -2;

	listen(soq, TOT_USERS);

	serverpoll[0].fd = soq;
	serverpoll[0].events = POLLIN;
	smax++;

	fprintf(stderr, "*SERVER* initialized sucessfully and going to poll()..\n");
	while (1) 
	{
		if (poll(serverpoll, smax, 0) < 0)
			return -2;

		for (users=0; users<smax; users++) 
		{
			usleep(2);

			if (serverpoll[users].revents & POLLIN) 
			{
				if (serverpoll[users].fd == serverpoll[0].fd) 
				{
					socklen_t sizestr = sizeof(struct sockaddr);
					newsoq = accept(serverpoll[0].fd, (struct sockaddr *)&client, &sizestr);
					if (newsoq == -1) 
						return -3;

					serverpoll[smax].fd = newsoq;
					serverpoll[smax].events = POLLIN;
					fprintf(stdout, "*%s* the ip *%s* connect in the server with fd *%d* as anonymous..\n",
						SERVER_NAME, inet_ntoa(client.sin_addr), serverpoll[smax].fd);

					snprintf(buf, sizeof(buf)-1, "Welcome to %s CHAT Server %s\n\0", SERVER_NAME, SERVER_VERSION);
					send(newsoq, buf, strlen(buf), 0);

					smax++;
				} else {
					memset(buf, 0, sizeof(buf)); rbytes = 0;
					rbytes = recv(serverpoll[users].fd, buf, sizeof(buf)-1, 0);
					if (!rbytes) {
						close(serverpoll[users].fd);

						serverpoll[users].fd = -1;
						serverpoll[users].events = -1;
						
						for(vrf=0;vrf<smax;vrf++)
						{
							if (serverpoll[vrf].fd == -1)
							{
								serverpoll[vrf].fd = serverpoll[vrf+1].fd;
								serverpoll[vrf].revents = serverpoll[vrf+1].revents;
							}
						}

						smax--;
						fprintf(stdout, "*SERVER* the ip *%s* is closed the connection..\n", inet_ntoa(client.sin_addr));
					}

					if (rbytes) {
						buf[rbytes - 2] = '\0';
						server_interpret(serverpoll[users].fd, buf);
					}
				}
			}
		}
	}
	
	return 0;
}
